package com.spzx.cart.service.impl;

import com.spzx.cart.api.domain.CartInfo;
import com.spzx.cart.service.ICartService;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.context.SecurityContextHolder;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.product.api.RemoteProductService;
import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.api.domain.vo.SkuPrice;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CartServiceImpl implements ICartService {

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    RemoteProductService remoteProductService;

    //返回购物车的key
    private String getCartKey(Long userId) {
        return "user:cart:" + userId;
    }

    //单品数量不能超过99
    //不同商品数量不能超过50
    @Override
    public void addToCart(Long skuId, Integer skuNum) {
        //步骤1 redis hash类型的key
        Long userId = SecurityContextHolder.getUserId();
        //String cartKey = "user:cart:" + userId;
        String cartKey = getCartKey(userId);

        //步骤2准备Redis Hash类型的 hashKey
        String hashKey = skuId.toString();

        //步骤3---准备CartInfo
        BoundHashOperations<String, String, CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);

        int threshold = 99;//单品的数量限制

        if (hashOperations.hasKey(hashKey)) {
            //在的话做修改
            CartInfo cartInfo = hashOperations.get(hashKey);
            int totalNum = cartInfo.getSkuNum() + skuNum;
            cartInfo.setSkuNum(totalNum > threshold ? threshold : totalNum);
            cartInfo.setUpdateTime(new Date());
            hashOperations.put(hashKey, cartInfo);

        } else {
            //不在的话做添加

            Long size = hashOperations.size();//不同商品的数量,上限是50

            if (size >= 50) {
                throw new ServiceException("商品数量不能超过50件");
            }

            CartInfo cartInfo = new CartInfo();
            cartInfo.setCreateTime(new Date());
            cartInfo.setUserId(userId);
            cartInfo.setSkuId(skuId);
            cartInfo.setSkuNum(skuNum);//默认值1

            //远程调用商品,根据skuId查询ProductSku对象
            R<ProductSku> productSkuR = remoteProductService.getProductSku(skuId, SecurityConstants.INNER);
            if (productSkuR.getCode() == R.FAIL) {//判断远程接口调用是否降级处理
                throw new ServiceException(productSkuR.getMsg());
            }
            ProductSku productSku = productSkuR.getData();
            cartInfo.setSkuName(productSku.getSkuName());
            cartInfo.setThumbImg(productSku.getThumbImg());
            cartInfo.setCartPrice(productSku.getSalePrice());
            cartInfo.setSkuPrice(productSku.getSalePrice());
            hashOperations.put(hashKey, cartInfo);

        }

    }

    @Override
    public List<CartInfo> cartList() {
        //步骤1准备Redis Hash类型的key
        Long userId = SecurityContextHolder.getUserId();
        String cartKey = getCartKey(userId);

        BoundHashOperations<String, String, CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        //从redis中获取数据旧价格数据
        List<CartInfo> cartInfoList = hashOperations.values();

        //更新商品实时价格,只更新JVM堆内存对象的商品最新价格,redis中的价格不变
        //批量获取商品最新价格

        if (!CollectionUtils.isEmpty(cartInfoList)) {
            List<Long> skuIdList = cartInfoList.stream().map((cartInfo) -> cartInfo.getSkuId()).toList();
            R<List<SkuPrice>> skuPriceListR = remoteProductService.getSkuPriceList(skuIdList, SecurityConstants.INNER);
            if (R.FAIL == skuPriceListR.getCode()) {
                throw new ServiceException(skuPriceListR.getMsg());
            }
            //数据库最新的价格
            List<SkuPrice> skuPriceList = skuPriceListR.getData();

            //为了从集合找数据方便,需要转成Map
            Map<Long, BigDecimal> skuIdToSalePriceMap =
                    skuPriceList.stream().collect(Collectors.toMap(SkuPrice::getSkuId, SkuPrice::getSalePrice));

            for (CartInfo cartInfo : cartInfoList) {
                cartInfo.setSkuPrice(skuIdToSalePriceMap.get(cartInfo.getSkuId()));
                 /*skuPriceList.stream().filter((skuPrice)->{
                    return skuPrice.getSkuId().equals(cartInfo.getSkuId())
                }).findFirst().ifPresent((skuPrice)->{
                    cartInfo.setSkuPrice(skuPrice.getSalePrice());
                });*/

            }
            return cartInfoList;
        }

        return new ArrayList<>();
    }

    @Override
    public void deleteCart(Long skuId) {
        //1.准备Redis Hash类型的key
        Long userId = SecurityContextHolder.getUserId();
        String cartKey =  getCartKey(userId);

        BoundHashOperations<String,String,CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        if(hashOperations.hasKey(skuId.toString())){
            hashOperations.delete(skuId.toString());
        }
    }

    @Override
    public void checkCart(Long skuId, Integer isChecked) {
        //1.准备Redis Hash类型的key
        Long userId = SecurityContextHolder.getUserId();
        String cartKey =  getCartKey(userId);

        String hashKey = skuId.toString();

        BoundHashOperations<String,String,CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        if(hashOperations.hasKey(hashKey)){
            CartInfo cartInfo = hashOperations.get(hashKey);
            cartInfo.setIsChecked(isChecked);
            hashOperations.put(hashKey, cartInfo);
        }
    }


    @Override
    public void allCheckCart(Integer isChecked) {
        //1.准备Redis Hash类型的key
        Long userId = SecurityContextHolder.getUserId();
        String cartKey =  getCartKey(userId);
        //redisTemplate.opsForHash().values()
        BoundHashOperations<String,String,CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);

        if(hashOperations.size()>0){
            List<CartInfo> cartInfoList = hashOperations.values();
            for (CartInfo cartInfo : cartInfoList) {
                cartInfo.setIsChecked(isChecked);
                hashOperations.put(cartInfo.getSkuId().toString(),cartInfo);
            }
        }

    }

    @Override
    public void clearCart() {
        //1.准备Redis Hash类型的key
        Long userId = SecurityContextHolder.getUserId();
        String cartKey =  getCartKey(userId);

        if(redisTemplate.hasKey(cartKey)){
            redisTemplate.delete(cartKey);
        }
    }

    @Override
    public List<CartInfo> getCartCheckdList(Long userId) {
        List<CartInfo> checkedCartList=new ArrayList<>();
        //准备Redis Hash类型的key
        String cartKey=getCartKey(userId);
        List<CartInfo> values = redisTemplate.opsForHash().values(cartKey);
        if (!CollectionUtils.isEmpty(values)){
            for(CartInfo cartInfo:values){
                if (cartInfo.getIsChecked().intValue()==1){
                    checkedCartList.add(cartInfo);
                }
            }
        }

        return checkedCartList;
    }

    //更新购物车价格
    @Override
    public Boolean updateCartPrice(Long userId) {
        //准备Redis Hash类型的key
        String cartKey=getCartKey(userId);//调用getCartKey()方法根据用户Id生成Redis中存储购物车数据的键名
        /*
        //List<CartInfo> values = redisTemplate.opsForHash().values(cartKey);
        使用 redisTemplate.opsForHash() 获取 Hash 操作对象
        调用 values(cartKey) 方法获取指定 Hash 结构中所有的值（value）
        返回的是该用户购物车中所有的商品信息列表，每个元素都是一个 CartInfo 对象
         */
        BoundHashOperations<String,String,CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> values = hashOperations.values();//购物车信息列表

        if (!CollectionUtils.isEmpty(values)){
            //批量获取商品的最新价格

            /*
            .stream()将List集合转换为Stream流
            map 是Stream的中间操作方法，用于转换流中的每个元素
            从每个 CartInfo 对象中提取 skuId（商品 ID），最终得到一个只包含商品 ID 的列表。
            对于流中的每个 CartInfo 对象，map 会调用该对象的 getSkuId() 方法，获取对应的商品 ID（Long 类型）
            CartInfo::getSkuId 是方法引用，等价于 lambda 表达式 cartInfo -> cartInfo.getSkuId()
            对流中的每个 CartInfo 对象调用 getSkuId() 方法
            将 Stream<CartInfo> 转换为 Stream<Long>，其中Long是SKU ID
            将Stream流收集为List集合
             */
            List<Long> skuIdList = values.stream().map(CartInfo::getSkuId).toList();

            /*
            R<List<SkuPrice>>：返回结果的封装类型（R是通用响应体）
            其中包含状态码、消息和数据（List<SkuPrice>，即商品价格列表）
             */
            R<List<SkuPrice>> skuPriceListR = remoteProductService.getSkuPriceList(skuIdList, SecurityConstants.INNER);//给我批量的id,得到批量的价格
            if (R.FAIL==skuPriceListR.getCode()){
                throw new ServiceException(skuPriceListR.getMsg());
            }
            //从成功的响应结果中提取商品价格数据列表
            List<SkuPrice> skuPriceList = skuPriceListR.getData();

            //商品的最新价格
            Map<Long, BigDecimal> skuIdToSalePriceMap = skuPriceList.stream().collect(Collectors.toMap(SkuPrice::getSkuId, SkuPrice::getSalePrice));


            for (CartInfo cartInfo : values) {
                //getIsChecked()返回Integer类型
                //intValue()将Integer转换为int进行比较
                //只处理被选中的商品
                if (cartInfo.getIsChecked().intValue()==1){
                    cartInfo.setCartPrice(skuIdToSalePriceMap.get(cartInfo.getSkuId()));
                    cartInfo.setSkuPrice(skuIdToSalePriceMap.get(cartInfo.getSkuId()));
                    //将更新后的购物车商品信息保存回Redis
                    hashOperations.put(cartInfo.getSkuId().toString(),cartInfo);
                }
            }
        }
        return true;
    }


    //删除购物车中勾选的商品
    @Override
    public Boolean deleteCartCheckedList(Long userId) {
        //1.准备Redis Hash类型的key
        String cartKey = getCartKey(userId);
        BoundHashOperations<String,String,CartInfo> hashOperations = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> values = hashOperations.values();
        if(!CollectionUtils.isEmpty(values)){
            for (CartInfo cartInfo : values) {
                if(cartInfo.getIsChecked().intValue()==1){
                    hashOperations.delete(cartInfo.getSkuId().toString());
                }
            }
        }
        return true;
    }


}